home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 476-500 / disk_494 / bref / bref2.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  25KB  |  963 lines

  1. /*   Program bref2.c -- makes the cross reference table. */
  2. /* Set TAB value to 3 for this listing. */
  3. /*        Invoked from bref.c which is main() */ 
  4.  
  5. extern char   Version[];
  6.  
  7. /*        Following are the original usage instructions for the CLI-only
  8.     version of BREF.  These instructions are still valid with the
  9.     present version.
  10.  
  11. **    This program reads standard input OR one or more files
  12. **    and prints the file(s) with line numbers added plus an
  13. **      alphabetic list of word references by line number.
  14. **
  15. **    To run:
  16. **  bref [-Q] [-Lnnn] [-Wnnn] [-Hccc] [-Tn] [-?] [-S] [-K] [-E] [file...]
  17. **
  18. **    Where 'file' must be ASCII, not binary -- AmigaBasic default.
  19. **    To save a Basic program in ASCII, enter in Basic output window:
  20. **        LIST ,"prog.name"
  21. **
  22. **    Options--first letter can be upper or lower case:
  23.  
  24. **    -Q    - don't print normal input file listing (Quiet).
  25. **    -Lnnn - set page Length to n instead of the default 66.
  26. **    -Wnnn - set page Width to n instead of the default 80.
  27. **         Maximum permitted page width is 132.
  28. **    -Hccc - set page Heading to 'ccc' rather than file names.
  29. **    -Tn   - set tab spaces to n instead of default 3
  30. **    -S    - Suppress form feeds; use for screen output
  31. **    -K    - show BASIC Keywords in crossref table
  32. **    -E    - print the input file 12 chars/in (Elite).  Default 10 cpi.
  33. **      -?    - display this list.
  34. */
  35.  
  36. #include <stdio.h>
  37. #include <ctype.h>
  38. #include <signal.h>
  39. #include <exec/types.h>
  40. #include <stat.h>
  41. #include <intuition/intuition.h>
  42.  
  43. #define MAXWORD        15    /* maximum chars in word */
  44. #define MAXPAGLINES    999    /* maximum posible lines in page */
  45. #define MINPAGLINES    4    /* minimum posible lines in page */
  46. #define MAXLINWIDTH    132    /* maximum posible chars in line */
  47. #define MINLINWIDTH    MAXWORD+12  /* minimum posible chars in line */
  48. #define MAXTABSIZE    132    /* maximum posible chars in tab */
  49. #define MINTABSIZE    1    /* minimum posible chars in tab */
  50.  
  51. #define igncase(c)    (isupper(c)? tolower(c) : (c))
  52.  
  53. #undef FALSE
  54. #undef TRUE
  55. #define FALSE    0
  56. #define TRUE    1
  57.  
  58. #ifdef    DEBUG
  59. #define debug(a,b)    fprintf(stderr,(a),(b))
  60. #else
  61. #define debug(a,b)
  62. #endif
  63.  
  64.  
  65. /*  global structures*/
  66.  
  67. #define LINLIST    struct    _linlist
  68. #define WRDLIST    struct    _wrdlist
  69.  
  70. struct    _linlist {        /* line number list node */
  71.     long     ln_no ;      /* line number */
  72.     LINLIST    *ln_next ;      /* next element pointer (or NULL) */
  73. } ;
  74.  
  75. struct    _wrdlist {        /* word list node */
  76.     char    *wd_wd ;      /* pointer to word */
  77.     char    *wd_lwd ;      /* pointer to word (lower case) */
  78.     LINLIST     wd_ln ;      /* first element of line list */
  79.     WRDLIST    *wd_low ;      /* lower child */
  80.     WRDLIST    *wd_hi ;      /* higher child */
  81. } ;
  82.  
  83.  
  84. /*  options*/
  85.  
  86. char    *Progname ;
  87. int      Tabsize     = 3 ;    /* default length of tab (-T) */
  88.  
  89. /*  extern variables -- values defined in main() */
  90.  
  91. extern int icon;                /* T = icon invoke, F = CLI invoke */ 
  92. extern char    *Filename ;        /* name of current input file */
  93. extern UBYTE out_name[];    /* Output -- CLI- to stdout */
  94.                                     /*                Icon- default to printer */
  95. extern char    Brefhdr[MAXLINWIDTH+1] ;/* report header */
  96. extern int    Quiet;            /* Print input file listing? (-q) */
  97. extern int    Maxlinwidth;    /* Chars in print line (-w) */
  98. extern int    Maxpaglines;    /* maximum lines in page (-L) */
  99. extern int    FormFeed;        /* Form feeds control (-S) */
  100. extern int    Elite;            /* Print source code in elite? (-E) */
  101. extern int    ShowKeyWords;    /* Show BASIC keywords in table? (-K)*/
  102. extern struct Window *w;    /* Pointer to Window */
  103. extern struct IntuitionBase *IntuitionBase;
  104.  
  105. /*  global variables*/
  106.  
  107. char    Date[30] ;        /* current or last file modify date */
  108. long    Hiline = 1L ;    /* current (and max.) input file line number */
  109. int    files=0 ;        /* count of source files */
  110. WRDLIST    *Wdtree = NULL ;    /* ptr to root node of binary word list */
  111. int    SkipREM  = FALSE;    /* Skip to EOL for REM */
  112. int    SkipDATA = FALSE;    /* For DATA, skip to EOL or colon */
  113. int    SaveMLW;        /* Save Max line width */
  114. FILE *output;        /* Output file pointer */
  115. FILE    *filep ;        /* Input file pointer */
  116.  
  117. /*  AmigaBASIC language reserved keywords */
  118. /*  Entered in binary search order.  This minimizes recursion */
  119. /*  during store of the keywords in the tree, thereby conserving on */
  120. /*  Stack usage. If the keywords are entered in alphabetic order, it */
  121. /*  causes a system crash (exceed Stack) during keyword store in the*/
  122. /*  tree.  There are 202 keywords in this list. */
  123.  
  124. char    *Bkeywords[] = {
  125.  
  126. /* Level 1 -- #101 */  "MOUSE",
  127. /* Level 2 -- #50 & #151 */  "EOF", "RESUME",
  128. /* Level 3 -- #25 75 126 177 */ "COLOR", "INT", "OPTION", "SUB",
  129. /* Level 4 */ 
  130. "BREAK", "DECLARE", "FRE","LOF","OBJECT.PLANES","POKEW","SIN","UCASE$",
  131. /* Level 5 */
  132. "AREAFILL", "CINT", "CVD",  "DEFSTR", "EXIT", "IF", "LIBRARY", "MERGE",
  133. "OBJECT.AY","OBJECT.VY", "PEEK", "PTAB","SADD","STATIC","TIME$","WEND",
  134. /* Level 6 */
  135. "AND",  "ATN",  "CHAIN", "CLNG", "COS",  "CVS", "DEFINT",  "EDIT",
  136. "ERL",  "FILES", "GOSUB", "INPUT", "LEFT$", "LLIST", "LPRINT", "MKI$", 
  137. "NEXT", "OBJECT.HIT", "OBJECT.START", "OCT$", "PAINT", "POINT","PRINT",
  138. "READ", "RND", "SCREEN", "SPACE$", "STOP", "TAB", "TRANSLATE$",
  139. "VARPTR", "WINDOW",
  140. /* Level 7 */
  141. "ABS", "APPEND", "AS", "BASE", "CALL", "CHDIR","CIRCLE","CLS","COMMON",
  142. "CSNG", "CVI", "DATA", "DEF", "DEFLNG", "DELETE", "ELSEIF", "EQV",
  143. "ERR", "EXP", "FIX", "FUNCTION", "GOTO", "IMP", "INPUT$",
  144. "KILL", "LEN", "LINE", "LOC", "LOG", "LSET", "MID$", "MKS$", "NAME",
  145. "NOT", "OBJECT.CLIP", "OBJECT.OFF", "OBJECT.PRIORITY", "OBJECT.STOP",
  146. "OBJECT.X", "ON", "OR", "PALETTE", "PEEKL", "POKE", "POS", "PRINT#",
  147. "PUT", "RESET", "RETURN", "RSET", "SAVE", "SGN", "SLEEP", "SPC",
  148. "STEP", "STRIG", "SWAP", "TAN", "TIMER", "TRON", "USING",
  149. "WAIT", "WHILE", "WRITE#",
  150. /* Level 8 -- everything else */
  151. "ALL", "AREA", "ASC", "BEEP", "CDBL", "CHR$", "CLEAR", "CLOSE",
  152. "COLLISION", "CONT", "CSRLIN", "CVL", "DATE$",  "DEFDBL", "DEFSNG",
  153. "DIM","ELSE", "END", "ERASE", "ERROR", "FIELD", "FOR", "GET", "HEX$",
  154. "INKEY$", "INPUT$", "INSTR", "LBOUND", "LET", "LIST", "LOAD",
  155. "LOCATE", "LPOS", "MENU", "MKD$", "MKL$", "MOD", "NEW","OBJECT.AX",
  156. "OBJECT.CLOSE", "OBJECT.ON", "OBJECT.SHAPE",  "OBJECT.VX",
  157. "OBJECT.Y", "OFF", "OPEN", "OUTPUT", "PATTERN", "PEEKW", "POKEL",
  158. "PRESET", "PSET", "RANDOMIZE", "REM", "RESTORE", "RIGHT$", "RUN","SAY",
  159. "SCROLL", "SHARED", "SOUND", "SQR", "STICK", "STR$", "STRING$",
  160. "SYSTEM", "THEN","TO", "TROFF", "UBOUND", "VAL", "WAVE", "WIDTH",
  161. "WRITE", "XOR",
  162.     0
  163. } ;
  164.  
  165.  
  166. /*  main2 - Store Basic keywords in tree.
  167.  *       Get program options and format heading lines.
  168.  *       Get words/line numbers from input file(s), store in tree.
  169.  *       Retrieve and print words in alphabetic order.  For each
  170.  *        word, print line numbers where word appears. */
  171.  
  172. main2(argc, argv)
  173. int     argc ;
  174. char    *argv[] ;
  175. {
  176.     char    wordfilebuf[BUFSIZ] ;
  177.     char    *getword(), *word ;
  178.     struct     stat    stbuf ;
  179.     long     time() ;
  180.     register cnt ;
  181.  
  182.     Progname = *argv ;        /* get invoked program name */
  183.     if (!icon)
  184.     {    output = stdout;
  185.         getcmd(argc, argv) ;    /* get CLI command line items */
  186.     }
  187.  
  188.         /* If the BASIC keywords are bypassed for the output */
  189.         /*   table, then store keywords in the tree with */
  190.         /*   line count = 0. */
  191.     if (!ShowKeyWords)
  192.        for (cnt=0 ; Bkeywords[cnt] ; cnt++)
  193.             storword(Bkeywords[cnt], 0L) ;
  194.  
  195.     listchr(-2);    /* clear output line */
  196.                     /* read and store files */
  197.     if (icon)
  198.     {
  199.         if (out_name[0] != '*')
  200.             output = fopen(out_name,"w");
  201.         else
  202.             output = stdout;
  203.         if (output == NULL)
  204.             fatal("Can't open output = %s",out_name);
  205.         if ((filep = fopen(Filename, "r")) == NULL)
  206.             fatal("Can't open input = %s", Filename) ;
  207.         if (! *Brefhdr)
  208.             strcpy(Brefhdr, Filename);
  209.         if (Elite == TRUE)
  210.         {    fprintf (output,"%s", "w");  /* Send elite code to printer*/
  211.             SaveMLW = Maxlinwidth;        /* Save Max Line Width */
  212.             Maxlinwidth = (Maxlinwidth * 6) / 5; /* New Max Line Width*/
  213.         }
  214.         stat(Filename, &stbuf) ;
  215.         mkdate((long)stbuf.st_mtime + 252460800) ;    /* This constant, */
  216.             /* (8 yrs in secs) changes the base year from 1978 to 1970. */
  217.         while (word = getword(filep))
  218.        {    storword(word, Hiline);
  219.              if (strcmp(word,"REM") == 0)
  220.                 SkipREM = TRUE;
  221.            if (strcmp(word,"DATA") == 0)
  222.                 SkipDATA = TRUE;
  223.        }
  224.         fclose(filep) ;
  225.     }
  226.     else
  227.     {
  228.         for (cnt=1 ; cnt < argc ; cnt++)
  229.             if (*argv[cnt] != '-')
  230.             {    files++ ;
  231.                 Filename = argv[cnt] ;
  232.                 if ((filep = fopen(Filename, "r")) == NULL)
  233.                     fatal("can't open %s", Filename) ;
  234.                 stat(Filename, &stbuf) ;
  235.                 mkdate((long)stbuf.st_mtime + 252460800);    /* This constant, */
  236.             /* (8 yrs in secs) changes the base year from 1978 to 1970. */
  237.  
  238.                 while (word = getword(filep))
  239.                {    storword(word, Hiline);
  240.                      if (strcmp(word,"REM") == 0)
  241.                         SkipREM = TRUE;
  242.                    if (strcmp(word,"DATA") == 0)
  243.                         SkipDATA = TRUE;
  244.                }
  245.                 fclose(filep) ;
  246.             }
  247.  
  248.         if (!files)            /* no files - read stdin */
  249.         {    if (*Brefhdr)
  250.                 Filename = Brefhdr ;
  251.             else
  252.                 Filename = "stdin" ;
  253.             mkdate(time( (long *)0)) ;
  254.             while (word = getword(stdin))
  255.                 storword(word, Hiline) ;
  256.         }
  257.     }
  258.     /*  print cross reference report */
  259.     bref(Wdtree) ;
  260.     fclose(output);
  261. }
  262.  
  263.  
  264. /*  getcmd - get arguments from command line & build page headings*/
  265.  
  266. getcmd(argc, argv)
  267. register argc ;
  268. register char    *argv[] ;
  269. {
  270.    register cnt ;
  271.  
  272.    debug("GETCMD(%d", argc) ;
  273.    debug(", %s)\n", argv[0]) ;
  274.  
  275.    *Brefhdr = '\0' ;
  276.                     /* get command options */
  277.    for (cnt=1; cnt < argc; cnt++)
  278.    {   if (*argv[cnt] == '-')
  279.        {   switch(igncase(argv[cnt][1]))
  280.        {  case 'q':
  281.         Quiet = TRUE ;
  282.         break ;
  283.  
  284.           case 'l':
  285.         Maxpaglines = atoi(&argv[cnt][2]) ;
  286.         if (Maxpaglines < MINPAGLINES
  287.             || Maxpaglines > MAXPAGLINES)
  288.             fatal("Bad -l value: %s", argv[cnt]) ;
  289.         break ;
  290.  
  291.           case 'w':
  292.         Maxlinwidth = atoi(&argv[cnt][2]) ;
  293.         if (Maxlinwidth < MINLINWIDTH
  294.             || Maxlinwidth > MAXLINWIDTH)
  295.             fatal("Bad -w value: %s", argv[cnt]) ;
  296.         break ;
  297.  
  298.           case 't':
  299.         Tabsize = atoi(&argv[cnt][2]);
  300.         if (Tabsize < MINTABSIZE
  301.             || Tabsize > MAXTABSIZE)
  302.             fatal ("Bad -T value: %s", argv[cnt]);
  303.         break;
  304.  
  305.           case 's':
  306.         FormFeed = FALSE;    /* Suppress form feeds */
  307.         break;
  308.  
  309.           case 'k':
  310.         ShowKeyWords = TRUE;   /* Show BASIC keywords */
  311.         break;
  312.  
  313.           case 'e':
  314.         Elite = TRUE;
  315.         fprintf (output,"%s", "w");  /* Send elite code to printer*/
  316.         break;
  317.  
  318.           case 'h':
  319.         strncpy(Brefhdr, &argv[cnt][2], MAXLINWIDTH) ;
  320.         Brefhdr[MAXLINWIDTH] = '\0' ;
  321.         break ;
  322.  
  323.           case '?':                /* help option */
  324.         usage();
  325.     fprintf (output," Options--1st letter either upper or lower case:\n\n");
  326.     fprintf (output," -Q    - don't print input file listing (Quiet)\n");
  327.     fprintf (output," -Lnnn - set page Length to n, not default 66.\n");
  328.     fprintf (output," -Wnnn - set page Width to n, not default 80.\n");
  329.     fprintf (output," -Hccc - set page Heading 'ccc', not file names\n");
  330.     fprintf (output," -Tn   - set tab spacing to n, not default 3\n");
  331.     fprintf (output," -S    - Suppress form feeds; use--screen output\n");
  332.     fprintf (output," -K    - show BASIC Keywords in CrossRef table\n");
  333.     fprintf (output," -E    - print input file 12 chars/inch (Elite)\n");
  334.     fprintf (output," -?    - display this list.\n");
  335.         exit(0);
  336.  
  337.           default:
  338.         usage();
  339.         exit(0);
  340.        }
  341.        }
  342.    }
  343.  
  344.     if (Elite)
  345.        { SaveMLW = Maxlinwidth;        /* Save Max Line Width */
  346.      Maxlinwidth = (Maxlinwidth * 6) / 5; /* New Max Line Width*/
  347.     }
  348.                 /* insert file names in hdr */
  349.    if (!*Brefhdr)
  350.        for (cnt=1; cnt < argc; cnt++)
  351.         if (*argv[cnt] != '-')
  352.            strjoin(Brefhdr, ' ', argv[cnt], MAXLINWIDTH) ;
  353. }
  354.  
  355. usage()
  356. {
  357. fprintf (output,"usage:\n\n");
  358. fprintf (output,"bref [-Q] [-Lnnn] [-Wnnn] [-Hccc] [-Tn] [-S] [-K] [-E] \
  359. [-?] [file ...]\n\n");
  360. }
  361.  
  362. #define    _listchr(chr)    if (!Quiet) listchr(chr)
  363.  
  364. /*  bypass - skip over constant:  hex, octal, decimal exponential */
  365.  
  366. bypass(filep,chr)
  367.   FILE  *filep;
  368.   register chr;
  369. {
  370.     _listchr(chr);
  371.     while (chr != EOF)
  372.     {
  373.         chr = getc(filep);
  374.         if ((chr >= '0' && chr <= '9') ||
  375.             (chr >= 'a' && chr <= 'f') ||
  376.             (chr >= 'A' && chr <= 'F'))
  377.         {  _listchr(chr);}    /* <--BRACKETS CRITICAL*/
  378.         else break;
  379.     }
  380.     return(chr);
  381. }
  382.  
  383. /*  getword - read, print and return next word from file*/
  384.  
  385. char *
  386. getword(filep)
  387. FILE    *filep ;
  388. {    static   int    first_read = TRUE;
  389.     static     char    wordbuf[MAXWORD+1] ;
  390.     static     int    savchr;
  391.     register char    *wp = wordbuf ;
  392.     register maxw = sizeof(wordbuf) ;
  393.     register chr ;
  394.     int     inword=0, lastchr=0, inquote = FALSE;
  395.     long     slineno ;
  396.  
  397. #define    _rtrnwrd(wp)         \
  398.    {   ungetc(chr, filep) ;    \
  399.     *(wp) = '\0' ;        \
  400.     savchr = chr;        \
  401.     return wordbuf ;    \
  402.    }
  403.  
  404.             /* Check for Intuition message CLOSEWINDOW to abort run */
  405.     if (icon) CheckAbort();
  406.  
  407.    while ((chr = getc(filep)) != EOF)
  408.    {
  409.     if (first_read)
  410.     { first_read = FALSE;
  411.       if (chr == 0xf5)
  412.       fatal ("File %s is binary, can't process--ASCII req.",Filename);
  413.     }
  414.  
  415.     if (SkipREM || SkipDATA)
  416.     {
  417.         if (savchr == '\n')
  418.         {    SkipREM = FALSE;/* This covers pathological case */
  419.             SkipDATA = FALSE;/* where nothing follows REM,DATA*/
  420.         }
  421.         else goto REM_DATA;    /* REM--skip to end of line*/
  422.                 /* DATA--skip to end of line or colon */
  423.     }
  424.  
  425.                 /* Test for hex constant (&Hnnn) */
  426.     if (igncase(chr) == 'h' && lastchr == '&' && inword == 0)
  427.         chr = bypass(filep,chr);
  428.  
  429.                 /* Test for octal constant (&Onnn) */ 
  430.     if (igncase(chr) == 'o' && lastchr == '&' && inword == 0)
  431.         chr = bypass(filep,chr);
  432.  
  433.     /* Test for decimal exponential constant (nnEnn or nn.Enn) */
  434.     if (igncase(chr) == 'e' && inword == 0 && 
  435.          (lastchr >= '0' && lastchr <= '9' || lastchr == '.'))
  436.         chr = bypass(filep,chr);
  437.  
  438.        if ((chr <= 'z' && chr >= 'a') || 
  439.        (chr <= 'Z' && chr >= 'A') )
  440.        {
  441.        if (maxw-- <= 1)
  442.         _rtrnwrd(wp) ;
  443.        *wp++ = chr ;        /* Add char to current word */
  444.        inword++ ;
  445.        _listchr(chr) ;
  446.        }
  447.  
  448.        else switch (chr)
  449.        {
  450.             /* These can't be 1st char in word -- */
  451.               /*   digit, period, suffixes for variable type */
  452.       case '0': case '1': case '2': case '3': case '4':
  453.       case '5': case '6': case '7': case '8': case '9':
  454.       case '.': case '%': case '&': case '!': case '#': case '$':
  455.           if (inword)
  456.         {   if (maxw-- <= 1)
  457.             _rtrnwrd(wp) ;
  458.            *wp++ = chr ;
  459.             }
  460.           _listchr(chr) ;
  461.           break ;
  462.                 /* newline - end current word */
  463.       case '\n':
  464.           if (inword)
  465.           _rtrnwrd(wp) ;
  466.           _listchr(chr) ;
  467.           Hiline++ ;
  468.           break ;
  469.             /* Apostrophe (') comment - print & bypass */
  470.                         /*     to end of the line. */
  471.       case '\'':
  472.           if (inword)
  473.           _rtrnwrd(wp) ;
  474. REM_DATA:    /* For REM, skip to end of line */
  475.         /* For DATA, skip to end of line or colon not in string */
  476.           _listchr(chr) ;
  477.           while ((chr = getc(filep)) != EOF)
  478.           {_listchr(chr);
  479.         if (chr == '\n')
  480.           {    Hiline++;
  481.             SkipREM = FALSE;
  482.             SkipDATA = FALSE;
  483.             break;
  484.           }
  485.         if (SkipDATA)
  486.         {        /* Check DATA for ':' not in string */
  487.             if (inquote)
  488.                 { if (chr == '"') inquote = FALSE; }
  489.             else if (chr == '"') inquote = TRUE;
  490.                       else if (chr == ':')
  491.                     {    SkipDATA = FALSE;
  492.                     break;
  493.                     }
  494.         }
  495.           }
  496.           if (chr == EOF)  ungetc(chr, filep);
  497.           break ;
  498.                 /* words in quotes - print & bypass */
  499.       case '"':
  500.           if (inword)
  501.           _rtrnwrd(wp) ;
  502.           _listchr(chr) ;
  503.           while ((chr = getc(filep)) != EOF)
  504.           {   _listchr(chr);
  505.               if (chr == '"')
  506.               break;
  507.           if (chr == '\n')   /* Making assumption here that */
  508.           {   Hiline++;      /* end of line is implied end of*/
  509.               break;         /* quote string. Apparently this*/
  510.           }             /* is what AmigaBasic does. */
  511.           }
  512.           if (chr == EOF) ungetc(chr,filep);
  513.           break ;
  514.  
  515.       default:
  516.           if (inword)
  517.           _rtrnwrd(wp) ;
  518.           _listchr(chr) ;
  519.           break ;
  520.        }        /* End of switch -- process char's */
  521.        lastchr = chr ;
  522.    }            /* End of while -- read char's */
  523.  
  524.    if (inword)
  525.        _rtrnwrd(wp) ;
  526.    _listchr(EOF) ;
  527.    return NULL ;
  528. }
  529.  
  530.  
  531. /*  listchr - list the input files one character at a time*/
  532.  
  533. static    Listpage = 0 ;
  534. static    Listpline = MAXPAGLINES ;
  535.  
  536. listchr(chr)
  537. register chr ;
  538. {
  539.     static    char     linebuf[MAXLINWIDTH*2], *lineptr=linebuf ;
  540.     static    lastchr=0, linecnt=0 ;
  541.     static  int    remain;
  542.     static  int    LNWid = 4;   /* Line number width on listing */
  543.             /* Changed from 6 in CREF to 4 in BREF */
  544.  
  545.     if (chr == -2)            /* clear line buffer */
  546.     {    setmem(linebuf,Maxlinwidth,' ');
  547.         return;
  548.     }
  549.  
  550.     if (chr == EOF)            /* EOF - print final line */
  551.     {    *lineptr = '\0' ;
  552.         listline(linebuf) ;
  553.         Listpage = 0 ;
  554.         Listpline = MAXPAGLINES ;
  555.         lineptr = linebuf ;
  556.         linecnt = 0 ;
  557.         return ;
  558.     }
  559.  
  560.     if (lineptr == linebuf)        /* new line - format line number */
  561.     {    ltoc(linebuf, Hiline, LNWid) ;
  562.         lineptr = linebuf + LNWid ;
  563.         *lineptr++ = ' ' ;
  564.         *lineptr++ = ' ' ;
  565.         linecnt = LNWid + 2;
  566.     }
  567.  
  568. #define    _lineoflo(ctr, newctr)        \
  569.     if ((ctr) >= Maxlinwidth)    \
  570.     {    *lineptr = '\0' ;    \
  571.         listline(linebuf) ;    \
  572.         lineptr = &linebuf[LNWid + 2] ;    \
  573.         linecnt = (newctr) ;    \
  574.     }
  575.  
  576.     switch (chr)
  577.     {                /* newline - print last line */
  578.        case '\n':
  579.         if (lastchr != '\f')
  580.         {    *lineptr = '\0' ;
  581.             listline(linebuf) ;
  582.         }
  583.         lineptr = linebuf ;
  584.         linecnt = 0 ;
  585.         break ;
  586.                  /* formfeed - print line and end page*/
  587.        case '\f':
  588.         if (linecnt != LNWid + 2)
  589.         {    *lineptr = '\0' ;
  590.             listline(linebuf) ;
  591.         }
  592.         Listpline = MAXPAGLINES ;  /* This triggers form feed*/
  593.                        /* on next entry--listline*/
  594.         lineptr = linebuf ;
  595.         linecnt = 0 ;
  596.         break ;
  597.                 /* tab - skip to next tab stop */
  598.        case '\t':
  599.         linecnt += Tabsize ;
  600.         remain =  linecnt % Tabsize ;
  601.         linecnt -= remain;
  602.         _lineoflo(linecnt, LNWid + 2) ;
  603.         lineptr += Tabsize ;
  604.         lineptr -= remain;
  605.         break ;
  606.                 /* backspace - print, but don't count*/
  607.        case '\b':
  608.         *lineptr++ = chr ;
  609.         break ;
  610.                     /* ctl-char - print as "^x" */
  611.              case 001: case 002: case 003:
  612.        case 004: case 005: case 006: case 007:
  613.                      case 013:
  614.                  case 015: case 016: case 017:
  615.        case 020: case 021: case 022: case 023:
  616.        case 024: case 025: case 026: case 027:
  617.        case 030: case 031: case 032: case 033:
  618.        case 034: case 035: case 036: case 037:
  619.         _lineoflo(linecnt+=2, LNWid + 4) ;
  620.         *lineptr++ = '^' ;
  621.         *lineptr++ = ('A'-1) + chr ;
  622.         break ;
  623.  
  624.        default:
  625.         if (isprint(chr))
  626.         {    _lineoflo(++linecnt, LNWid + 3) ;
  627.             *lineptr++ = chr ;
  628.         }
  629.         else        /* non-ascii chars - print as "\nnn" */
  630.         {    _lineoflo(linecnt+=4, LNWid + 6) ;
  631.             *lineptr++ = '\\' ;
  632.             *lineptr++ = '0' + ((chr & 0300) >> 6) ;
  633.             *lineptr++ = '0' + ((chr & 070) >> 3) ;
  634.             *lineptr++ = '0' + (chr & 07) ;
  635.         }
  636.         break ;
  637.     }
  638.     lastchr = chr ;
  639. }
  640.  
  641.  
  642.         /* print a completed line from the input file */
  643. listline(line)
  644. register char    *line ;
  645. {
  646.     if (*line)
  647.     {    if (++Listpline >= (Maxpaglines-8))
  648.         {    if (FormFeed)
  649.                 if (files >1 || Listpage) putc('\f',output) ;
  650.             fprintf (output,"\nBREF %s %s %s  Page %d\n\n",
  651.                Version, Date, Filename, ++Listpage) ;
  652.             Listpline = 0 ;
  653.         }
  654.         strcat(line,"\n");    /* Append newline char */
  655.         fputs(line,output) ;
  656.         listchr(-2);    /* clear line buffer */
  657.     }
  658. }
  659.  
  660.  
  661. /*  storword - store word and line # in binary word tree or word file*/
  662.  
  663. storword(word, lineno)
  664. register char    *word ;
  665. long     lineno ;
  666. {
  667.     char     lword[MAXWORD+1] ;
  668.     register char    *cp1, *cp2 ;
  669.     WRDLIST    *addword() ;
  670.  
  671.                 /* convert word to lower case */
  672.     for (cp1=word, cp2=lword ; *cp2++ = igncase(*cp1) ; cp1++)
  673.         ;
  674.  
  675.                     /* store words and lineno */
  676.     Wdtree = addword(Wdtree, word, lword, lineno) ;
  677. }
  678.  
  679.  
  680. /*  addword - add word and line# to in-core word list*/
  681.  
  682. WRDLIST *
  683. addword(wdp, word, lword, lineno)
  684. register WRDLIST *wdp ;
  685. char    *word, *lword ;
  686. long     lineno ;
  687. {
  688.     char    *malloc() ;
  689.     int     comp ;
  690.                     /* insert new word into list */
  691.     if (wdp == NULL)
  692.     {    register wordlen = strlen(word) + 1 ;
  693.  
  694.         wdp = (WRDLIST *)malloc((wordlen * 2)+sizeof(WRDLIST));
  695.         if (wdp == NULL)
  696.             goto nomemory ;
  697.  
  698.         wdp->wd_wd  = (char *)wdp + sizeof(WRDLIST) ;
  699.         wdp->wd_lwd = wdp->wd_wd + wordlen ;
  700.         strcpy(wdp->wd_wd,  word) ;
  701.         strcpy(wdp->wd_lwd, lword) ;
  702.  
  703.         wdp->wd_hi = wdp->wd_low = NULL ;
  704.         wdp->wd_ln.ln_no = lineno ;
  705.         wdp->wd_ln.ln_next = NULL ;
  706.     }
  707.  
  708.                     /* word matched in list? */
  709.     else if (((comp = strcmp(lword, wdp->wd_lwd)) == 0)
  710.           && ((comp = strcmp(word,  wdp->wd_wd))  == 0))
  711.     {    register LINLIST *lnp, **lnpp ;
  712.  
  713.         if (wdp->wd_ln.ln_no)
  714.         {              /* add line# to linked list*/
  715.             lnp = &wdp->wd_ln ;
  716.             do
  717.             {    if (lineno == lnp->ln_no)
  718.                     return wdp ;
  719.                 lnpp = &lnp->ln_next ;
  720.             } while ((lnp = *lnpp) != NULL) ;
  721.  
  722.             *lnpp = (LINLIST *)malloc(sizeof(LINLIST)) ;
  723.             if ((lnp = *lnpp) == NULL)
  724.                 goto nomemory ;
  725.             lnp->ln_no = lineno ;
  726.             lnp->ln_next = NULL ;
  727.         }
  728.     }
  729.  
  730.     else if (comp < 0)    /* search for word in children */
  731.         wdp->wd_low = addword(wdp->wd_low, word, lword,lineno);
  732.     else
  733.         wdp->wd_hi = addword(wdp->wd_hi, word, lword, lineno) ;
  734.  
  735.     return wdp ;
  736.                 /* not enough memory - convert to -b */
  737. nomemory:
  738.     fatal("not enough memory for in-core word list") ;
  739. }
  740.  
  741.  
  742. /*  bref - print cross reference report from internal word list*/
  743.  
  744. #define MAXLNOS 2000        /* maximum line nos. for a word */
  745. long    Linenos[MAXLNOS] ;    /* list of line numbers for a word */
  746.  
  747. bref(wdtree)
  748. register WRDLIST *wdtree ;
  749. {
  750.     if (Elite)
  751.     {fprintf (output,"%s","w");   /* Turn off elite for printer */
  752.      Maxlinwidth = SaveMLW;  /* Restore original Max line width*/
  753.     }
  754.  
  755.     breftree(wdtree) ;
  756.     if (FormFeed)
  757.         putc ('\f',output); /*Final form feed after print x-ref table*/
  758. }
  759.  
  760.  
  761. breftree(wdp)            /* recursively print word tree nodes */
  762. register WRDLIST *wdp ;
  763. {
  764.     register LINLIST *lnp ;
  765.     register nos ;
  766.  
  767.     if (wdp != NULL)
  768.     {    breftree(wdp->wd_low) ;    /* print lower children */
  769.  
  770.         nos = 0 ;
  771.         if (Linenos[0] = wdp->wd_ln.ln_no)
  772.         {    lnp = &wdp->wd_ln ;
  773.             while ((lnp = lnp->ln_next) != NULL)
  774.                 if (nos < (MAXLNOS-2))
  775.                     Linenos[++nos] = lnp->ln_no ;
  776.             printword(wdp->wd_wd, nos) ;
  777.         }
  778.  
  779.         breftree(wdp->wd_hi) ;    /* print higher children */
  780.     }
  781. }
  782.  
  783. static int SkipFF = FALSE;
  784.  
  785. /*  printword - print a word and all its line number references*/
  786.  
  787. printword(word, nos)
  788. char    *word ;
  789. register nos ;
  790. {
  791.     static    firstime=TRUE, linecnt, maxlnos, lnosize ;
  792.     register cnt ;
  793.  
  794.     if (icon) CheckAbort();        /* Check for CLOSEWINDOW to abort run */
  795.     if (firstime)
  796.     {    firstime = FALSE ;
  797.         if (Quiet) SkipFF = TRUE;/* If didn't print input, skip 1st FormFeed*/
  798.         linecnt = Maxpaglines ;
  799.         for (lnosize=1 ; Hiline ; lnosize++)
  800.             Hiline /= 10L ;
  801.         maxlnos = (Maxlinwidth - (MAXWORD+7)) / lnosize ;
  802.     }
  803.  
  804.     if (linecnt >= (Maxpaglines - 5))
  805.     {    printheads() ;
  806.         linecnt = 5 ;
  807.     }
  808.  
  809.     fprintf (output,"%-15s%5d  ", word, ++nos) ;
  810.     Linenos[nos] = 0 ;
  811.  
  812.     for (nos=0, cnt=0 ; Linenos[nos] ; nos++)
  813.     {    if (++cnt > maxlnos)
  814.         {    cnt = 1 ;
  815.             if (linecnt++ >= (Maxpaglines - 4))
  816.             {    printheads() ;
  817.                 linecnt = 5 ;
  818.                 fprintf (output,"%-15s(cont) ", word);
  819.             }
  820.             else
  821.                 fprintf (output,"\n%22s", " ") ;
  822.         }
  823.         fprintf (output,"%*ld", lnosize, Linenos[nos]) ;
  824.     }
  825.     putc('\n',output) ;
  826.  
  827.     linecnt++ ;
  828. }
  829.  
  830.  
  831. /*  printheads - print page headings*/
  832.  
  833. printheads()
  834. {
  835.     static    page=0 ;
  836.     long    time() ;
  837.  
  838.     if (!page)
  839.         mkdate(time( (long *)0)) ;
  840.  
  841.     if (SkipFF) SkipFF = FALSE;        /* if Quiet, skip 1st FormFeed */
  842.     else if (FormFeed) putc('\f',output) ;        /* Form feed */
  843.     fprintf (output,"\nBREF %s %s %.*s  Page %d\n\n",
  844.        Version, Date, (Maxlinwidth-36), Brefhdr, ++page) ;
  845.     fprintf (output,"word             refs    line numbers\n\n") ;
  846. }
  847.  
  848.  
  849. /*  ltoc - store ASCII equivalent of long value in given field*/
  850.  
  851. ltoc(fld, lval, len)
  852. register char    *fld ;
  853. register long    lval ;
  854. register len ;
  855. {
  856.     fld += len ;
  857.     while (len-->0)
  858.         if (lval)
  859.         {    *--fld = '0' + (lval%10L) ;
  860.             lval /= 10L ;
  861.         }
  862.         else
  863.             *--fld = ' ' ;
  864. }
  865.  
  866.  
  867. /*  mkdate - build time/date for use in heading lines*/
  868.  
  869. mkdate(atime)
  870. long    atime ;
  871. {
  872.     long    mtime ;
  873.     char    *cp, *ctime() ;
  874.  
  875.     debug("MKDATE(%ld)\n", atime) ;
  876.  
  877.     mtime = atime ;
  878.     cp = ctime(&mtime) ;
  879.     *(cp+24) = ' ' ;        /* clear newline */
  880.     strcpy(cp+16, cp+19) ;        /* shift over seconds */
  881.     strcpy(Date, cp+4) ;
  882. }
  883.  
  884.  
  885. /*  strjoin - join "str1" to "str2" (separated by "sep")
  886.  *    Truncate if necessary to "max" chars.*/
  887.  
  888. strjoin(str1, sep, str2, max)
  889. register char    *str1, *str2;
  890. char    sep ;
  891. register max ;
  892. {
  893.     if (*str2)
  894.     {    if (*str1)
  895.         {    while (*str1++)
  896.                 if (--max <= 0)
  897.                     goto oflo ;
  898.             max--, str1-- ;
  899.             *str1++ = sep ;
  900.         }
  901.         while (*str1++ = *str2++)
  902.             if (--max <= 0)
  903.                 goto oflo ;
  904.     }
  905.     return ;
  906.  
  907. oflo:
  908.     *--str1 = '\0' ;
  909.     return ;
  910. }
  911.  
  912. CheckAbort()    /* Check for CLOSEWINDOW message to abort run */
  913. {
  914.  static struct IntuiMessage *msg;    /* Intuition message pointer */
  915.  static ULONG class;
  916.  static BOOL fin = FALSE;
  917.  
  918.     while (msg = (struct IntuiMessage *) GetMsg(w->UserPort))
  919.     {
  920.         class = msg->Class;
  921.         ReplyMsg(msg);
  922.  
  923.         switch(class)
  924.         {
  925.             case CLOSEWINDOW:
  926.                 fin = TRUE;
  927.                 break;
  928.             default:
  929.                 break;
  930.         }
  931.     }
  932.     if (fin)
  933.     {                                            /* Abort run -- clean up & quit */
  934.         fclose(filep);
  935.         fclose(output);
  936.         CloseWindow(w);
  937.         CloseLibrary(IntuitionBase);
  938.         exit(0);
  939.     }
  940. }
  941.  
  942. /*  fatal - print standard error msg and halt process*/
  943.  
  944. fatal(ptrn, data1)
  945. register char    *ptrn, *data1;
  946. {
  947.     if (icon)
  948.     {
  949.         fclose(output);
  950.         ErrMsg(0,ptrn,data1);    /* In main() mod, use requester */
  951.                                     /* to display the error message */
  952.             /* 1st arg (= 0) signals close of Window, Intuition */
  953.     }
  954.     else
  955.     {
  956.         fprintf(stderr, "%s: ", Progname) ;
  957.         fprintf(stderr, ptrn, data1) ;
  958.         putc('\n', stderr) ;
  959.         fclose(output);
  960.         exit(1);
  961.     }
  962. }
  963.